package com.ssau.expert.util;

import com.ssau.expert.app.AppConfig;
import com.ssau.expert.common.RuleDTO;
import com.ssau.expert.entity.Ship;
import com.ssau.expert.entity.ShipName;
import com.ssau.expert.entity.ShipProfile;
import org.apache.commons.io.FileUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentFactory;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

/**
 * Author: Sergey42
 * Date: 25.11.13 22:56
 */
public class FileIO {

    public static List<Ship> loadShips() {
        try {
            InputStreamReader isr = new FileReader(AppConfig.SHIPS_XML);
            SAXReader saxReader = new SAXReader();

            Document document = saxReader.read(isr);
            Element root = document.getRootElement();
            List<Ship> ships = new ArrayList<>();
            for (Element wkElem : (List<Element>) root.elements("ship")) {
                Ship ship = new Ship();
                ship.setShipProfile(ShipProfile.fromLocal(wkElem.attributeValue("profile")));
                ship.setShipName(ShipName.fromId(Integer.valueOf(wkElem.attributeValue("shipNameId"))));
                ship.setWaterVolume(Integer.valueOf(wkElem.attributeValue("waterVolume")));
                ship.setMaxDistance1(Integer.valueOf(wkElem.attributeValue("md1")));
                ship.setMaxDistance2(Integer.valueOf(wkElem.attributeValue("md2")));
                ship.setCfMaxDistance1(Integer.valueOf(wkElem.attributeValue("cfmd1")));
                ship.setCfMaxDistance2(Integer.valueOf(wkElem.attributeValue("cfmd2")));
                ship.setMaxStaff1(Integer.valueOf(wkElem.attributeValue("ms1")));
                ship.setMaxStaff2(Integer.valueOf(wkElem.attributeValue("ms2")));
                ship.setCfMaxStaff1(Integer.valueOf(wkElem.attributeValue("cfms1")));
                ship.setCfMaxStaff2(Integer.valueOf(wkElem.attributeValue("cfms2")));
                ships.add(ship);
            }
            return ships;
        } catch (IOException e) {
            System.out.println(e.getMessage());
            return new ArrayList<Ship>();
        } catch (DocumentException e) {
            System.out.println(e.getMessage());
            return new ArrayList<Ship>();
        }
    }

    public static void saveShips(List<Ship> ships) {
        try {
            FileWriter osw = new FileWriter(AppConfig.SHIPS_XML);
            OutputFormat format = OutputFormat.createPrettyPrint();
            XMLWriter writer = new XMLWriter(osw, format);
            Document d = DocumentFactory.getInstance().createDocument();
            d.setName("ships.xml");
            d.setXMLEncoding("UTF-8");

            Element root = d.addElement("ships");

            for (Ship ship : ships) {
                Element element = root.addElement("ship");
                element.addAttribute("profile", ship.getShipProfile().getName());
                element.addAttribute("shipNameId", String.valueOf(ship.getShipName().getId()));
                element.addAttribute("waterVolume", String.valueOf(ship.getWaterVolume()));
                element.addAttribute("md1", String.valueOf(ship.getMaxDistance1()));
                element.addAttribute("cfmd1", String.valueOf(ship.getCfMaxDistance1()));
                element.addAttribute("md2", String.valueOf(ship.getMaxDistance2()));
                element.addAttribute("cfmd2", String.valueOf(ship.getCfMaxDistance2()));
                element.addAttribute("ms1", String.valueOf(ship.getMaxStaff1()));
                element.addAttribute("cfms1", String.valueOf(ship.getCfMaxStaff1()));
                element.addAttribute("ms2", String.valueOf(ship.getMaxStaff2()));
                element.addAttribute("cfms2", String.valueOf(ship.getCfMaxStaff2()));

            }
            writer.write(d);
            writer.flush();
        } catch (IOException e) {
            System.out.println(e.getMessage());
        }
    }

    public static Integer readUndefinedBarrier() {
        try {
            @SuppressWarnings("unchecked")
            List<String> lines = FileUtils.readLines(new File(AppConfig.UNDEFINED_BARRIER_FILE));
            if (!lines.isEmpty()) {
                return Integer.valueOf(lines.get(0));
            }
        } catch (IOException e) {
            System.out.println(e.getMessage());
        }
        return null;
    }

    public static void setUndefinedBarrier(int undefinedBarrier) {
        try {
            FileUtils.writeStringToFile(new File(AppConfig.UNDEFINED_BARRIER_FILE), String.valueOf(undefinedBarrier));
        } catch (IOException e) {
            System.out.println(e.getMessage());
        }
    }

    public static void saveCoeffs(List<RuleDTO> ruleDTOList) {
        try {
            List<String> lines = new ArrayList<>(ruleDTOList.size());
            for (RuleDTO ruleDTO : ruleDTOList) {
                String line = "";
                for (Object value : ruleDTO.values) {
                    line += value + ";";
                }
                lines.add(line.substring(0, line.length() - 1));
            }

            FileUtils.writeLines(new File(AppConfig.COEFFS_FILE), lines);
        } catch (Exception ex) {
            System.out.println(ex.getMessage());
        }
    }

    public static List<RuleDTO> getCoeffs() {
        try {
            @SuppressWarnings("unchecked")
            List<String> lines = FileUtils.readLines(new File(AppConfig.COEFFS_FILE));
            if (!lines.isEmpty()) {
                List<RuleDTO> dtos = new ArrayList<>(lines.size());
                int id = 0;
                for (String line : lines) {
                    RuleDTO ruleDTO = new RuleDTO(id++);

                    String[] vals = line.split(";", -1);
                    for (int i = 0; i < vals.length; i++) {
                        String val = vals[i];
                        ruleDTO.values[i] = (i != RuleDTO.SHIP) ? Integer.valueOf(val) : val;
                    }
                    dtos.add(ruleDTO);
                }
                return dtos;
            }
        } catch (IOException e) {
            System.out.println(e.getMessage());
        }
        return new ArrayList<>();
    }
}
